package main

import (
	"cm2"
	"cm2/service"
	"cm2/service/log"
	"cm2/terminal/console/win/global"
	"cm2/terminal/console/win/taskserv"
	"cm2/terminal/console/win/webserv"
	cmutil "cm2/util"
	"fmt"
	"os"
	"os/signal"
	"path"
	"syscall"

	"github.com/go-xorm/xorm"

	_ "github.com/mattn/go-sqlite3"
)

// Run 启动服务
func run() {
	defer func() {
		if recoverErr := recover(); recoverErr != nil {
			log.DefaultLogger().Fatalf("application failed, unhandled panic: %v", recoverErr)
			return
		}
	}()

	go func() {
		ch := make(chan os.Signal, 1)
		signal.Notify(ch,
			// kill -SIGINT XXXX or Ctrl+c
			os.Interrupt,
			syscall.SIGINT, // register that too, it should be ok
			// os.Kill  is equivalent with the syscall.Kill
			os.Kill,
			syscall.SIGKILL, // register that too, it should be ok
			// kill -SIGTERM XXXX
			syscall.SIGTERM,
		)
		select {
		case <-ch:
			shutdown()
		}
	}()

	log.DefaultLogger().Info("console service's starting, initializing...")

	// 初始化主服务实例
	service.Init()

	// 启动 job service
	taskserv.RunJobService(initJobLogProvider())

	// 启动 task tcp server
	taskserv.RunTaskService()

	// 启动 console service
	webserv.RunConsoleWebService(initConsoleWebDBProvider())

	if <-global.WebServShutdown && <-global.TaskServShutdown {
		log.DefaultLogger().Info("console service has been shutdown")
	}
	//log.DefaultLogger().Info("console service has been shutdown")
}

// Shutdown 停止端
func shutdown() {
	ws := service.DefaultWebapp()
	if ws != nil {
		log.DefaultLogger().Info("shutting down console web service...")
		ws.Shutdown()
	}
	global.WebServShutdown <- true
	ts := service.DefaultTaskServer()
	if ts != nil {
		log.DefaultLogger().Info("shutting down task server service...")
		ts.Shutdown()
	}
	js := service.DefaultJobService()
	if js != nil {
		log.DefaultLogger().Info("shutting down job service...")
		js.Shutdown()
	}
	global.TaskServShutdown <- true
}

func initJobLogProvider() *xorm.Engine {
	// 开启log数据库连接，如果出现错误，直接抛出致命异常
	jsConfig := service.DefaultConfig["jobService"].(map[string]interface{})
	logPath := path.Join(cmutil.GetWorkingPath(), jsConfig["log"].(string))
	jbp, jbpError := initSqlite3Db(logPath)
	if jbpError != nil {
		em := fmt.Sprintf("connect to joblog provider failed: %s %v", logPath, jbpError)
		log.DefaultLogger().Error(em)
		panic(em)
	}

	return jbp
}

func initConsoleWebDBProvider() *xorm.Engine {
	cwConfig := service.DefaultConfig["consoleWebServer"].(map[string]interface{})
	dbPath := path.Join(cmutil.GetWorkingPath(), cwConfig["depot"].(string))
	jbp, jbpError := initSqlite3Db(dbPath)
	if jbpError != nil {
		em := fmt.Sprintf("connect to console web dbprovider failed: %s %v", dbPath, jbpError)
		log.DefaultLogger().Error(em)
		panic(em)
	}

	return jbp
}

func initSqlite3Db(path string) (*xorm.Engine, error) {
	var jbp *xorm.Engine
	var jbpError error

	if exists, _ := cmutil.PathExists(path); !exists {
		cmutil.Mkdir(cmutil.GetDir(path))
		if f, _ := os.OpenFile(path, os.O_CREATE, 0777); f != nil {
			f.Close()
		}
	}

	if jbp, jbpError = xorm.NewEngine("sqlite3", path); jbpError != nil {
		return nil, jbpError
	}
	if jbpError = jbp.Ping(); jbpError != nil {
		return nil, jbpError
	}
	if cmutil.GetGOENV() == cm2.DEV {
		jbp.ShowSQL(true)
		// js.jbp.SetLogger(xorm.NewLo) 好像不需要设置日志
	}

	return jbp, jbpError
}

func main() {
	run()
}
